﻿using Gavel.Common.Utilities.Const;
using Gavel.Common.Utilities.Extension;

namespace Gavel.ModLink.Model;

/// <summary>
/// 预置报文
/// </summary>
public class WriteMessage
{
    /// <summary>
    /// 从机地址
    /// </summary>
    public byte Slave { get; set; }

    /// <summary>
    /// 寄存器地址
    /// </summary>
    public ushort Address { get; set; }

    /// <summary>
    /// 寄存器值
    /// </summary>
    public ushort Value { get; set; }

    /// <summary>
    /// 协议类型
    /// </summary>
    public ProtocolType Protocol { get; set; }

    /// <summary>
    /// 功能码
    /// </summary>
    public FunctionType Function { get; set; }

    /// <summary>
    /// CRC大小端
    /// </summary>
    public Endian Endian { get; set; }

    /// <summary>
    /// 报文字节数组
    /// </summary>
    public byte[] Message
    {
        get
        {
            List<byte> message = Protocol switch
            {
                ProtocolType.Rtu => CreateRtuMessage(),
                _ => CreateTcpMessage()
            };

            return message.ToArray();
        }
    }

    /// <summary>
    /// 创建TCP协议报文
    /// </summary>
    /// <returns>TCP协议报文</returns>
    private List<byte> CreateTcpMessage()
    {
        List<byte> message = [];
        message.AddRange(((ushort)Random.Shared.Next(ushort.MaxValue)).ToBytes());
        message.AddRange(((ushort)0).ToBytes());
        ushort length = (ushort)(Function == FunctionType.WriteMultiple ? 9 : 6);
        message.AddRange(length.ToBytes());
        message.Add(Slave);
        message.Add((byte)Function);
        message.AddRange(Address.ToBytes());
        if (Function == FunctionType.WriteMultiple)
        {
            message.AddRange(((ushort)1).ToBytes());
            message.Add(2);
        }

        message.AddRange(Value.ToBytes());
        return message;
    }

    /// <summary>
    /// 创建RTU协议报文
    /// </summary>
    /// <returns>RTU协议报文</returns>
    private List<byte> CreateRtuMessage()
    {
        List<byte> message =
        [
            Slave,
            (byte)Function
        ];
        message.AddRange(Address.ToBytes());
        if (Function == FunctionType.WriteMultiple)
        {
            message.AddRange(((ushort)1).ToBytes());
            message.Add(2);
        }

        message.AddRange(Value.ToBytes());
        message.AddRange(message.ToArray().CalculateCrc(Endian));
        return message;
    }
}